#!/usr/bin/python
#
# Copyright (c) 2009 Julius Volz
# See LICENSE for details.

import os
import xapian
import config, debug


class Index(object):
  def __init__(self, dataset, paths):
    self.dataset = dataset
    self.paths = paths
    self.databases = {}

    resources = None
    
    for path in paths:
      if not self.index_exists(path):
        if resources is None:
          debug.log(2, 'Loading destination resources...')
          resources = dataset.resources()
          debug.log(2, 'found %s.\n' % len(resources))
        debug.log(2, 'Building index over path "%s"...' % path.path)
        self.build_index(path, resources)
        debug.log(2, 'done.\n')
      else:
        debug.log(2, 'Using existing index over path "%s".\n' % path.path)

      database = xapian.Database(self.index_dir(path))
      self.databases[path] = database

  def index_exists(self, path):
    if os.path.isdir(self.index_dir(path)):
      return True
    else:
      return False

  def index_dir(self, path):
    return '%s%sidx_%s' % (config.index_dir, os.sep, self.hash_key(path))

  def hash_key(self, path):
    return hash((self.dataset.hash_key(), path.path))

  def build_index(self, path, resources):
    os.mkdir(self.index_dir(path))
    database = xapian.WritableDatabase(self.index_dir(path), xapian.DB_CREATE_OR_OPEN)

    indexer = xapian.TermGenerator()

    for resource in resources:
      value = self.evaluate_path(path, resource, self.dataset)
      if value is None:
        continue

      debug.log(4, 'Path %s, indexing %s, value: "%s"\n' % (path.path, resource, repr(value)))

      doc = xapian.Document()
      for word in value.split(' '):
        database.add_spelling(word)
      doc.set_data(resource)

      indexer.set_document(doc)
      indexer.index_text(value)

      # Add the document to the database.
      database.add_document(doc)

  def search(self, path, resource, dataset, limit=10):
    value = self.evaluate_path(path, resource, dataset)
    if value is None:
      return []

    resources = set()

    for dst_path in self.paths:
      enquire = xapian.Enquire(self.databases[dst_path])
      qp = xapian.QueryParser()
      qp.set_database(self.databases[dst_path])
      query = qp.parse_query(value, qp.FLAG_SPELLING_CORRECTION)
      corrected = qp.get_corrected_query_string()
      if corrected:
        query = qp.parse_query(corrected)
      #print "Parsed query is: %s" % query.get_description()

      # Find the top 10 results for the query.
      enquire.set_query(query)

      for hit in enquire.get_mset(0, limit):
        resources.add(hit.document.get_data())

    #print "SEARCH: %s, FOUND: %s" % (repr(value), str(resources))
    return resources

  def evaluate_path(self, path, resource, dataset):
    bindings = {
      dataset.var: [{
        'type': 'uri',
        'value': resource,
        'dataset': dataset
      }]
    }
    values = path.evaluate(bindings)
    if len(values) == 0:
      return None
    else:
      return ' '.join([value['value'] for value in values])
